﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.Win32;

namespace Foundation
{
    public enum TrayNotifyLevel
    {
        OnlyShowNotifications = 0,
        HideIconAndNotifications = 1,
        ShowIconAndNotifications = 2,
    };

    public static class TrayNotify
    {
        private const string TrayNotifyValueName = "IconStreams";
        private const string TrayNotifyKeyNew = @"Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify";
        private const string TrayNotifyKeyOld = @"Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify\";

        public static void RestartExplorer()
        {
            var processes = Process.GetProcessesByName("explorer").ToList();
            processes.ForEach(p => p.Kill());
            Process.Start("explorer");
        }

        public static TrayNotifyLevel GetLevel(string executablePath)
        {
            return ManageLevel(executablePath, TrayNotifyLevel.OnlyShowNotifications, false);
        }

        public static TrayNotifyLevel SetLevel(string executablePath, TrayNotifyLevel level)
        {
            return ManageLevel(executablePath, level, true);
        }

        private static TrayNotifyLevel ManageLevel(string executablePath, TrayNotifyLevel level, bool set)
        {
            using (var trayNotifyKey =
                Registry.CurrentUser.OpenSubKey(TrayNotifyKeyOld, RegistryKeyPermissionCheck.ReadWriteSubTree) ??
                Registry.CurrentUser.OpenSubKey(TrayNotifyKeyNew, RegistryKeyPermissionCheck.ReadWriteSubTree))
            {
                if (trayNotifyKey == null) return TrayNotifyLevel.OnlyShowNotifications;
                var bytes = ((byte[])trayNotifyKey.GetValue(TrayNotifyValueName)).Select(Rot13).ToArray();
                var text = Encoding.Unicode.GetString(bytes);
                var index = text.IndexOf(executablePath, StringComparison.Ordinal);
                if (index < 0) return TrayNotifyLevel.OnlyShowNotifications;
                var chars = text.ToCharArray();
                if (set)
                {
                    chars[index + 264] = (char) level;
                    bytes = Encoding.Unicode.GetBytes(chars).Select(Rot13).ToArray();
                    trayNotifyKey.SetValue(TrayNotifyValueName, bytes);
                }

                var notificationLevel = chars[index + 264];
                return (TrayNotifyLevel) notificationLevel;
            }
        }

        private static byte Rot13(byte byteToRot)
        {
            if (byteToRot > 64 && byteToRot < 91)
                return (byte) ((byteToRot - 64 + 13)%26 + 64);

            if (byteToRot > 96 && byteToRot < 123)
                return (byte) ((byteToRot - 96 + 13)%26 + 96);

            return byteToRot;
        }
    }
}
